#include <sys/types.h>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "Task3.cpp"
using namespace std;
vector<task_t> tasks;
//先描述
class channel
{
    public:
    channel(int wfd,pid_t slaverid,const string processname) //构造
    :_wfd(wfd),_slaverid(slaverid),_processname(processname)
    {

    }
    public:
    int _wfd;//管道写端描述符
    pid_t _slaverid;//对应子进程
    string _processname;//进程名字
};
int processnum=10;//一次创建的进程数
void slaver()
{
    while(true)//子进程不停读，除非读到文件末尾即写端关闭无数据可读
    {
        int taskcode=0;//
        ssize_t size=read(0,&taskcode,sizeof(int));
        if(size==sizeof(int))
        {
            //读取成功，执行任务
            if(taskcode>0&&taskcode<=4)
            tasks[taskcode-1]();
        }
        else if(size==0)//读到0表示写端关闭，读到文件末尾
        break;
    }
}
int InitProcessPool(vector<channel>*channels)
{
    vector<int> oldfd;//用来关闭历史打开的写端管道
    for(int i=0;i<processnum;i++)//批量创建子进程
    {
        int pipefd[2]={0};//临时数据
        int n=pipe(pipefd);//创建子进程前建好管道通信
        if(n<0)return 1;//返回值小于0创建失败
        pid_t id=fork();
        if(id<0)return 2;//返回值小于0创建进程失败
        else if(id==0)
        {
            //关掉继承的父管道写端
            cout<<"child" << getpid()<<" close history fd: ";
            for(auto &e:oldfd)
            {
                close(e);
                cout<<e<<" ";
            }
            cout<<endl;
            //child   子读父写，子关闭写入端口
            close(pipefd[1]);
            dup2(pipefd[0],0);//重定向，让子进程没有管道概念 直接从标准输入流读
            //子进程读取任务码执行任务
            slaver();
            close(pipefd[0]);
            exit(0);//执行完任务关闭读端并退出程序
        }
        else
        {
            //farther  子读父写，父关闭读端口
            close(pipefd[0]);
            //写入字段
            std::string processname="process"+std::to_string(i);
            channels->push_back(channel(pipefd[1],id,processname));
            oldfd.push_back(pipefd[1]);//把写一个子进程即将继承的写端管道fd记录，等子进程创建的时候就把它关了
            sleep(1);
        }
    }
}
void Menu()
{
    cout<<"##############################"<<endl;
    cout<<"## 1.刷新蓝buff  2.刷新红buff #"<<endl;
    cout<<"## 3.刷新地图    4.刷新技能cd #"<<endl;
    cout<<"########## 0.退出 ############"<<endl;
    cout<<"##############################"<<endl;

}
//输入const &
//输出 *
// 输入输出 &
int ControlProcess(const vector<channel>&channels)
{
    int select=0;
    int which=0;
    while(true)
    {
    //1.选择任务  让用户自己决定
    Menu();//菜单
    cin>>select;
    if(select<=0||select>4)break;
    //2.选择进程
    //3.发送任务(往管道写入任务码)
    ssize_t n=write(channels[which]._wfd,&select,sizeof(int));
    if(n<0)return 3;
    ++which;
    which%=channels.size();//子进程轮流获取任务
    }
    return 0;
}
void QuitProcess(const vector<channel>&channels)
{
    //1.关闭写入端口
    for(const auto&e:channels)
    {
        close(e._wfd);
        waitpid(e._slaverid,nullptr,0);
    }

    //2.等待子进程
    // for(const auto&e:channels)
    // {
    //     waitpid(e._slaverid,NULL,0);
    // }
}
int main()
{
    loadtask(&tasks);//加载任务
    vector<channel> channels;//再组织
    InitProcessPool(&channels);//初始化
    ControlProcess(channels);//控制进程
    QuitProcess(channels);//清理工作
    return 0;
}